package com.ruoyi.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.business.domain.*;
import com.ruoyi.business.mapper.RechargeOrderMapper;
import com.ruoyi.business.service.BusinessService;
import com.ruoyi.business.service.RechargeOrderService;
import com.ruoyi.business.service.SettlementService;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.security.Md5Utils;
import com.ruoyi.system.domain.SysDictData;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.SysConfigService;
import com.ruoyi.system.service.SysDictDataService;
import com.ruoyi.system.service.SysUserService;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 话费充值订单Service业务层处理
 * 
 * @author xx
 * @date 2020-03-22
 */
@Service
public class RechargeOrderServiceImpl implements RechargeOrderService {
    private static final Logger log = LoggerFactory.getLogger(RechargeOrderServiceImpl.class);
    @Autowired
    private RechargeOrderMapper rechargeOrderMapper;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private BusinessService businessService;
    @Autowired
    private SysDictDataService sysDictDataService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SettlementService settlementService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * 查询话费充值订单
     * 
     * @param id 话费充值订单ID
     * @return 话费充值订单
     */
    @Override
    public RechargeOrder selectRechargeOrderById(Long id) {
        return rechargeOrderMapper.selectRechargeOrderById(id);
    }

    /**
     * 查询话费充值订单列表
     * 
     * @param rechargeOrder 话费充值订单
     * @return 话费充值订单
     */
    @Override
    public List<RechargeOrder> selectRechargeOrderList(RechargeOrder rechargeOrder) {
        if (rechargeOrder.getUserId() != null) {
            SysUser sysUser = new SysUser();
            sysUser.setPid(rechargeOrder.getUserId());
            rechargeOrder.setUserIds(sysUserService.selectUserList(sysUser).stream().map(SysUser::getUserId).collect(Collectors.toList()));
        }
        return rechargeOrderMapper.selectRechargeOrderList(rechargeOrder);
    }

    /**
     * 新增话费充值订单
     * 
     * @param rechargeOrder 话费充值订单
     * @return 结果
     */
    @Override
    public int insertRechargeOrder(RechargeOrder rechargeOrder) {
        rechargeOrder.setCreateTime(DateUtils.getNowDate());
        rechargeOrder.setState(1);

        SysDictData sdBusinessType = sysDictDataService.selectDictDataByType("sd_business_type").stream().filter(sysDictData -> "0".equals(sysDictData.getDictValue())).findAny().orElse(null);
        if (Objects.isNull(sdBusinessType)) {
            throw new BusinessException("业务不存在");
        } else if ("1".equals(sdBusinessType.getStatus())) {
            throw new BusinessException(sdBusinessType.getDictLabel() + "已停用");
        }

        SysDictData sdRechargeChannel = sysDictDataService.selectDictDataByType("sd_recharge_channel").stream().filter(sysDictData -> rechargeOrder.getRechargeChannel().toString().equals(sysDictData.getDictValue())).findAny().orElse(null);
        if (Objects.isNull(sdRechargeChannel)) {
            throw new BusinessException("充值通道不存在");
        } else if ("1".equals(sdRechargeChannel.getStatus())) {
            throw new BusinessException(sdRechargeChannel.getDictLabel() + "已停用");
        }

        Business business = businessService.selectBusinessByUserId(0, rechargeOrder.getRechargeChannel(), rechargeOrder.getUserId());
        if (Objects.isNull(business)) {
            throw new BusinessException("未开通此商家业务");
        } else if (business.getStatus() == 1) {
            throw new BusinessException("商家业务已禁用");
        }

        SysUser sysUser = sysUserService.selectUserById(rechargeOrder.getUserId());
        if ("1".equals(sysUser.getStatus())) {
            throw new BusinessException("用户已禁用");
        }

        double price = business.getPrices().stream().filter(businessMoney -> StringUtils.equals(businessMoney.getValue(), rechargeOrder.getRechargeMoney().toString())).findAny().map(BusinessMoney::getMoney).orElse(0D);
        if (price == 0) {
            throw new BusinessException("充值金额有误");
        }
        if (price > sysUser.getBalance()) {
            throw new BusinessException("余额不足");
        }

        rechargeOrder.setBusinessId(business.getId());
        if (StringUtils.isBlank(rechargeOrder.getOrderNum())) {
            rechargeOrder.setOrderNum(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")) + (new Random().nextInt(900) + 100));
        }
        rechargeOrder.setMoney(price);
        int count = rechargeOrderMapper.insertRechargeOrder(rechargeOrder);
        CompletableFuture.runAsync(() -> postRecharge(rechargeOrder, sysUser), threadPoolTaskExecutor);
        return count;
    }

    private void postRecharge(RechargeOrder rechargeOrder, SysUser sysUser) {
        String url = sysConfigService.selectConfigByKey("sd.recharge.order");
        Map<String, String> params = new HashMap<>(8);
        params.put("merchantId",sysConfigService.selectConfigByKey("sd.recharge.merchantid"));
        params.put("mobile", rechargeOrder.getMobile());
        params.put("tradeNoThird", rechargeOrder.getOrderNum());
        // 字典表定义充值通道 偶数是快充
        params.put("orderType", (rechargeOrder.getRechargeChannel() % 2 == 0) ? "1" : "2");
        List<SysDictData> rechargeMoneys = sysDictDataService.selectDictDataByType("sd_recharge_money");
        params.put("amount", rechargeMoneys.stream().filter(sysDictData -> StringUtils.equals(sysDictData.getDictValue(), rechargeOrder.getRechargeMoney().toString())).findAny().map(SysDictData::getDictLabel).orElse(null));
        params.put("notifyUrl",sysConfigService.selectConfigByKey("sd.recharge.notifyurl"));
        String merchantkey = sysConfigService.selectConfigByKey("sd.recharge.merchantkey");
        params.put("signstr", Md5Utils.hash(params.get("merchantId") + params.get("orderType") + params.get("mobile") + params.get("tradeNoThird") + params.get("amount") + params.get("notifyUrl") + merchantkey));
        log.info("话费充值参数 rechargeOrder={} params={}", rechargeOrder.toString(), params.toString());
        try {
            HttpResponse response = HttpUtils.post(url, null, params, true);
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            log.info("话费充值返回 result={}", result);
            JSONObject jsonObject = JSON.parseObject(result);
            Integer code = jsonObject.getInteger("code");
            RechargeOrder order = new RechargeOrder();
            order.setId(rechargeOrder.getId());
            if (code != 200) {
                order.setState(3);
            } else {
                String orderNumUp = jsonObject.getJSONObject("body").getString("tradeNoSelf");
                order.setOrderNumUp(orderNumUp);
            }
            order.setUpdateBy("同步返回");
            order.setRechargeResult(jsonObject.getString("msg"));
            updateRechargeOrder(order);
        } catch (Exception e) {
            RechargeOrder order = new RechargeOrder();
            order.setId(rechargeOrder.getId());
            order.setState(3);
            order.setRechargeResult("话费充值异常" + e.getMessage());
            order.setUpdateBy("同步返回");
            updateRechargeOrder(order);
            throw new BusinessException(e.getMessage() == null ? "充值异常" : e.getMessage());
        }
    }

    /**
     * 修改话费充值订单
     * 
     * @param rechargeOrder 话费充值订单
     * @return 结果
     */
    @Override
    public int updateRechargeOrder(RechargeOrder rechargeOrder) {
        rechargeOrder.setUpdateTime(DateUtils.getNowDate());
        return rechargeOrderMapper.updateRechargeOrder(rechargeOrder);
    }

    /**
     * 删除话费充值订单对象
     * 
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteRechargeOrderByIds(String ids) {
        return rechargeOrderMapper.deleteRechargeOrderByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除话费充值订单信息
     * 
     * @param id 话费充值订单ID
     * @return 结果
     */
    @Override
    public int deleteRechargeOrderById(Long id) {
        return rechargeOrderMapper.deleteRechargeOrderById(id);
    }

    @Override
    public void doNotify(Map<String, String[]> params) {
        log.info("话费充值异步通知参数 params={}", JSON.toJSONString(params));
        String orderNum = params.get("tradeNoThird")[0];
        String msg = params.get("msg")[0];
        String sign = params.get("signstr")[0];
        String code = params.get("code")[0];

        String merchantkey = sysConfigService.selectConfigByKey("sd.recharge.merchantkey");
        String signstr;
        RechargeOrder order = new RechargeOrder();
        Map<String, String> map = new HashMap<>();
        boolean isSuccess = StringUtils.equals(code, "200");
        if (isSuccess) {
            map.put("code", "2");
        } else {
            map.put("code", "3");
        }
        signstr = Md5Utils.hash(code + orderNum + msg + merchantkey);
        if (StringUtils.equals(sign, signstr)) {
            RechargeOrder rechargeOrder = rechargeOrderMapper.selectRechargeOrderByOrderNum(orderNum);
            SysUser sysUser = sysUserMapper.selectUserById(rechargeOrder.getUserId());
            order.setOrderNum(orderNum);
            if (isSuccess) {
                order.setState(2);

                // 修改余额
                SysUser user = new SysUser(sysUser.getUserId());
                user.setBalance(BigDecimal.valueOf(sysUser.getBalance() - rechargeOrder.getMoney()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                sysUserService.updateUserInfo(user);
                // 保存余额变更记录
                BalanceChange balanceChange = new BalanceChange();
                balanceChange.setUserId(sysUser.getUserId());
                balanceChange.setReason("话费充值中扣减 充值记录表id=" + rechargeOrder.getId());
                balanceChange.setBefor(sysUser.getBalance());
                balanceChange.setAfter(user.getBalance());
                balanceChange.setDiff(BigDecimal.valueOf(balanceChange.getAfter() - balanceChange.getBefor()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                balanceChange.setCreateBy(rechargeOrder.getCreateBy());
                sysUserMapper.insertBalance(balanceChange);
            } else {
                order.setState(3);
            }
            order.setUpdateBy("异步回调");
            updateRechargeOrder(order);
            String notifyUrl = rechargeOrder.getNotifyUrl();
            if (StringUtils.isNotBlank(notifyUrl)) {
                try {
                    HttpResponse response = HttpUtils.post(notifyUrl, null, map, true);
                    log.info(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                } catch (Exception e) {
                    log.error("通知下游系统失败", e);
                }
            }
            /*if (StringUtils.equals(status, "4")) {
                // 扣除余额
                RechargeOrder rechargeOrder = rechargeOrderMapper.selectRechargeOrderByOrderNum(orderNum);
                SysUser user = sysUserService.selectUserById(rechargeOrder.getUserId());
                SysUser sysUser = new SysUser(rechargeOrder.getUserId());
                sysUser.setBalance(user.getBalance() - rechargeOrder.getMoney());
                sysUser.setUpdateBy("异步回调");
                sysUserService.updateUserInfo(sysUser);
            }*/
        } else {
            throw new BusinessException("签名校验异常");
        }
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int settle(RechargeOrder rechargeOrder) {
        if (StringUtils.isBlank(rechargeOrder.getIds())) {
            throw new BusinessException("入参不能为空");
        }

        Long[] ids = Convert.toLongArray(rechargeOrder.getIds());
        List<RechargeOrder> list = rechargeOrderMapper.selectRechargeOrderByIds(ids);
        if (list.isEmpty()) {
            throw new BusinessException("入参有误");
        }

        if (list.stream().anyMatch(order -> order.getState() != 2 || order.getSettleStatus() == 1)) {
            throw new BusinessException("只能结算充值成功且未结算的记录");
        }

        list.forEach(order -> {
            Long userId = order.getUserId();
            Business business = businessService.selectBusinessById(order.getBusinessId());
            settleRecharge(order, rechargeOrder.getUpdateBy(), userId, business);
        });

        for (Long id : ids) {
            RechargeOrder order = new RechargeOrder();
            order.setId(id);
            order.setSettleStatus(1);
            rechargeOrderMapper.updateRechargeOrder(order);
        }
        return ids.length;
    }

    @Override
    public String importOrder(List<RechargeOrder> orderList, Long operId, String operName) {
        orderList.forEach(rechargeOrder -> {
            rechargeOrder.setUserId(operId);
            rechargeOrder.setCreateBy(operName);
            insertRechargeOrder(rechargeOrder);
        });
        return "操作成功";
    }

    @Override
    public RechargeOrder selectByUserIdAndOrderNum(Long userId, String orderNum) {
        return rechargeOrderMapper.selectByUserIdAndOrderNum(userId, orderNum);
    }

    private void settleRecharge(RechargeOrder order, String createBy, Long userId, Business business) {
        SysUser sysUser = sysUserService.selectUserById(userId);
        Optional.ofNullable(sysUser).map(SysUser::getPid).ifPresent(pid -> {
            Business pBusiness = businessService.selectBusinessByUserId(0, order.getRechargeChannel(), pid);
            if (Objects.nonNull(pBusiness)) {
                Double money = business.getPrices().stream().filter(businessMoney -> Objects.equals(order.getRechargeMoney().toString(), businessMoney.getValue())).map(BusinessMoney::getMoney).findAny().orElse(0D);
                Double pMoney = pBusiness.getPrices().stream().filter(businessMoney -> Objects.equals(order.getRechargeMoney().toString(), businessMoney.getValue())).map(BusinessMoney::getMoney).findAny().orElse(0D);

                Settlement settlement = new Settlement();
                settlement.setUserId(pid);
                settlement.setOrderId(order.getId());
                settlement.setBusinessId(business.getId());
                settlement.setCommission(BigDecimal.valueOf(money - pMoney).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                settlement.setBusinessType(0);
                settlement.setCreateBy(createBy);
                try {
                    settlementService.insertSettlement(settlement);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    if (e instanceof DuplicateKeyException) {
                        throw new BusinessException("不能重复结算");
                    } else {
                        throw e;
                    }
                }
                settleRecharge(order, createBy, pid, pBusiness);
            }
        });
    }
}
